package com.bstek.uflo.console.view.template;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.DataResolver;
import com.bstek.dorado.annotation.Expose;
import com.bstek.dorado.data.type.EntityDataType;
import com.bstek.dorado.data.type.property.BasePropertyDef;
import com.bstek.dorado.data.type.property.Mapping;
import com.bstek.dorado.view.View;
import com.bstek.dorado.view.manager.ViewConfig;
import com.bstek.dorado.view.widget.HtmlContainer;
import com.bstek.dorado.view.widget.base.toolbar.Button;
import com.bstek.dorado.view.widget.form.autoform.AutoForm;
import com.bstek.dorado.view.widget.form.autoform.AutoFormElement;
import com.bstek.dorado.web.DoradoContext;
import com.bstek.uflo.command.impl.jump.JumpNode;
import com.bstek.uflo.model.ProcessDefinition;
import com.bstek.uflo.model.task.Task;
import com.bstek.uflo.model.task.TaskState;
import com.bstek.uflo.model.variable.Variable;
import com.bstek.uflo.process.flow.SequenceFlowImpl;
import com.bstek.uflo.process.node.FormElement;
import com.bstek.uflo.process.node.Node;
import com.bstek.uflo.process.node.TaskNode;
import com.bstek.uflo.process.security.Authority;
import com.bstek.uflo.service.ProcessService;
import com.bstek.uflo.service.TaskOpinion;
import com.bstek.uflo.service.TaskService;

/**
 * @author Jacky.gao
 * @since 2013年9月25日
 */
@Component("defaultFormTemplateViewConfigListener")
public class DefaultFormTemplateViewConfigListener {
	@Autowired
	@Qualifier(ProcessService.BEAN_ID)
	private ProcessService processService;
	@Autowired
	@Qualifier(TaskService.BEAN_ID)
	private TaskService taskService;
	public void onInit(ViewConfig viewConfig) throws Exception{
		HttpServletRequest request=DoradoContext.getCurrent().getRequest();
		String taskId=request.getParameter("taskId");
		String processId=request.getParameter("processId");
		if(StringUtils.isEmpty(taskId) || StringUtils.isEmpty(processId)){
			return;
		}
		ProcessDefinition pd=processService.getProcessById(Long.valueOf(processId));
		Task task=taskService.getTask(Long.valueOf(taskId));
		HtmlContainer titleContainer=(HtmlContainer)viewConfig.getView().getComponent("htmlContainerTitle");
		String desc=task.getDescription();
		if(StringUtils.hasText(desc)){
			titleContainer.setContent("<h2>"+task.getTaskName()+"</h2>"+task.getDescription()+"");			
		}else{
			titleContainer.setContent("<h2>"+task.getTaskName()+"</h2>");						
		}
		boolean canForward=taskService.canWithdraw(task);
		viewConfig.getView().setTags(String.valueOf(canForward));
		initButtons(viewConfig.getView(),task,canForward);
		Node node=pd.getNode(task.getNodeName());
		List<FormElement> formElements=pd.getStartNode().getFormElements();
		if(node instanceof TaskNode){
			TaskNode taskNode=(TaskNode)node;
			if(taskNode.getFormElements()!=null && taskNode.getFormElements().size()>0){
				formElements=taskNode.getFormElements();
			}			
		}
		if(formElements==null || formElements.size()==0)return;
		
		AutoForm form=(AutoForm)viewConfig.getView().getComponent("autoFormEntity");
		EntityDataType entityDataType=(EntityDataType)viewConfig.getDataType("dataTypeEntity");
		for(FormElement element:formElements){
			BasePropertyDef def=new BasePropertyDef(element.getName());
			def.setLabel(element.getCaption());
			def.setDataType(viewConfig.getDataType(element.getDataType()));
			def.setDefaultValue(element.getDefaultValue());
			if(element.getAuthority().equals(Authority.Read)){
				def.setReadOnly(true);
			}
			if(element.getMappings()!=null && element.getMappings().size()>0){
				def.setMapping(getMapping(element.getMappings()));				
			}
			if(element.isRequired()){
				def.setRequired(true);
			}
			entityDataType.addPropertyDef(def);
			
			AutoFormElement autoFormElement=new AutoFormElement();
			autoFormElement.setName(element.getName());
			autoFormElement.setProperty(element.getName());
			autoFormElement.setEditorType(element.getEditorType());
			form.addElement(autoFormElement);
		}
	}
	
	private void initButtons(View view,Task task,boolean canForward){
		Button toolBarButtonStartTask=(Button)view.getComponent("toolBarButtonStartTask");
		Button toolBarButtonCompleteTask=(Button)view.getComponent("toolBarButtonCompleteTask");
		Button toolBarButtonForward=(Button)view.getComponent("toolBarButtonForward");
		Button toolBarButtonJump=(Button)view.getComponent("toolBarButtonJump");
		if(task.getState().equals(TaskState.Created) || task.getState().equals(TaskState.Reserved)){
			toolBarButtonStartTask.setDisabled(false);
			toolBarButtonCompleteTask.setDisabled(true);
			toolBarButtonForward.setDisabled(true);								
			toolBarButtonJump.setDisabled(true);
		}else{
			toolBarButtonStartTask.setDisabled(true);		
			toolBarButtonCompleteTask.setDisabled(false);
			if(canForward){
				toolBarButtonForward.setDisabled(false);				
			}else{
				toolBarButtonForward.setDisabled(true);								
			}
			toolBarButtonJump.setDisabled(false);
		}
	}
	
	private Mapping getMapping(List<com.bstek.uflo.process.node.Mapping> mappings){
		Mapping result=new Mapping();
		result.setKeyProperty("key");
		result.setValueProperty("label");
		List<Map<String,String>> list=new ArrayList<Map<String,String>>();
		for(com.bstek.uflo.process.node.Mapping mapping:mappings){
			Map<String,String> map=new HashMap<String,String>();
			map.put("key", mapping.getKey());
			map.put("label", mapping.getLabel());
			list.add(map);
		}
		result.setMapValues(list);
		return result;
	}
	
	@DataProvider
	public Map<String,Object> loadEmptyData(String processInstanceId){
		List<Variable> variables=processService.getProcessVariables(Long.valueOf(processInstanceId));
		Map<String,Object> map=new HashMap<String,Object>();
		for(Variable variable:variables){
			map.put(variable.getKey(), variable.getValue());
		}
		return map;
	}
	
	@DataResolver
	public void rollback(Map<String,Object> entity,String taskId,String processInstanceId){
		if(taskService.canWithdraw(Long.valueOf(taskId))){
			saveEntity(entity, processInstanceId);
			taskService.withdraw(Long.valueOf(taskId));
		}else{
			throw new IllegalStateException("当前任务不能回退");
		}
	}
	
	@DataResolver
	public void forward(Map<String,Object> entity,String taskId,String targetNodeName){
		taskService.forward(Long.valueOf(taskId), targetNodeName, entity);
	}
	
	@DataProvider
	public List<JumpNode> loadForwardNodes(String taskId){
		List<JumpNode> names=taskService.getAvaliableForwardTaskNodes(Long.valueOf(taskId));
		return names;
	}
	
	@Expose
	public void startTask(String taskId){
		taskService.start(Long.valueOf(taskId));
	}
	
	@DataResolver
	public void completeTask(Map<String,Object> entity,Map<String,Object> parameter){
		String opinion=(String)parameter.get("opinion");
		String flowName=(String)parameter.get("flowName");
		String taskId=(String)parameter.get("taskId");
		taskService.complete(Long.valueOf(taskId), flowName,entity,new TaskOpinion(opinion));
	}
	
	@DataProvider
	public List<SequenceFlowImpl> getTaskFlowNames(String taskId){
		Task task=taskService.getTask(Long.valueOf(taskId));
		ProcessDefinition pd=processService.getProcessById(task.getProcessId());
		List<SequenceFlowImpl> list=new ArrayList<SequenceFlowImpl>();
		for(SequenceFlowImpl flow:pd.getNode(task.getNodeName()).getSequenceFlows()){
			if(StringUtils.hasText(flow.getName()) && !flow.getName().startsWith(TaskService.TEMP_FLOW_NAME_PREFIX)){
				list.add(flow);
			}
		}
		return list;
	}
	
	
	@DataResolver
	public void saveEntity(Map<String,Object> entity,String processInstanceId){
		processService.saveProcessVariables(Long.valueOf(processInstanceId), entity);
	}
}
